1 module unde.games.dizzy.omega.rope;
2 
3 import derelict.opengl3.gl;
4 
5 import std.algorithm;
6 import std.conv;
7 import std.math;
8 import std.stdio;
9 import unde.games.object;
10 import unde.games.renderer;
11 import unde.games.collision_detector;
12 import unde.games.object;
13 import unde.global_state;
14 
15 class Rope:StaticGameObject
16 {
17     float by, segl;
18     float[3][] rope;
19 
20     static int num;
21     static GLuint rope_texture;
22     int number;
23     int static_segments;
24 
25     int cut_segm = -1;
26     
27     this(MainGameObject root, float[3] rope_start, float[3] rope_end, float by, uint length, float segl,
28          int static_segments = 1)
29     {
30         x = rope_end[0];
31         y = rope_end[1];
32         z = rope_end[2];
33         
34         this.by = by;
35         this.segl = segl;
36         if (length > 1)
37         {
38             float rx = rope_start[0];
39             float ry = rope_start[1];
40             float rz = rope_start[2];
41             if (static_segments == 1)
42             {
43                 foreach (i; 0..length)
44                 {
45                     rope ~= [rx + (x-rx)*i/(length-1),
46                              ry + (y-ry)*i/(length-1),
47                              rz + (z-rz)*i/(length-1)];
48                 }
49             }
50             else
51             {
52                 foreach (i; 0..static_segments)
53                 {
54                     rope ~= [rx + (x-rx)*i/(static_segments-1),
55                              ry + (y-ry)*i/(static_segments-1),
56                              rz + (z-rz)*i/(static_segments-1)];
57                 }
58                 
59                 foreach (i; static_segments..length)
60                 {
61                     rope ~= [x, y, z];
62                 }
63                 
64                 cut_segm = length - 1;
65             }
66         }
67 
68         this.static_segments = static_segments;
69 
70         if (num == 0)
71         {
72             rope_texture = load_texture("models/dizzy/rope.png");
73         }
74         number = num++;
75         
76         super(root);
77     }
78 
79     void reinit()
80     {
81         if (rope.length > 1)
82         {
83             float rx = rope[0][0];
84             float ry = rope[0][1];
85             float rz = rope[0][2];
86             
87             if (static_segments == 1)
88             {
89                 foreach (i; 0..rope.length)
90                 {
91                     rope[i] = [rx + (x-rx)*i/(rope.length-1),
92                              ry + (y-ry)*i/(rope.length-1),
93                              rz + (z-rz)*i/(rope.length-1)];
94                 }
95             }
96             else
97             {
98                 foreach (i; 0..static_segments)
99                 {
100                     rope [i] = [rx + (x-rx)*i/(static_segments-1),
101                              ry + (y-ry)*i/(static_segments-1),
102                              rz + (z-rz)*i/(static_segments-1)];
103                 }
104                 
105                 foreach (i; static_segments..rope.length)
106                 {
107                     rope[i] = [x, y, z];
108                 }
109                 
110                 cut_segm = cast(int) rope.length - 1;
111             }
112         }
113     }
114 
115     float length(float[3] v)
116     {
117         return sqrt(v[0]^^2 + v[1]^^2 + v[2]^^2);
118     }
119     
120     void normalize(ref float[3] v)
121     {
122         float len = length(v);
123         v[] /= len;
124     }
125 
126     float[3] produce(float[3] v1, float[3] v2)
127     {
128         return [ v1[2]*v2[1] - v1[1]*v2[2], v1[0]*v2[2] - v1[2]*v2[0], v1[1]*v2[0] - v1[0]*v2[1] ];
129     }
130 
131     void cut(int segm)
132     {
133         cut_segm = segm;
134     }
135     
136     override void draw(GlobalState gs)
137     {
138         draw_part(gs, 0, rope.length - 1);
139     }
140 
141     void draw_part(GlobalState gs, size_t a, size_t b)
142     {
143         if (rope.length < 2) return;
144         
145         glEnable(GL_LIGHTING);
146         glDisable(GL_COLOR_MATERIAL);
147         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [0.8f, 0.8f, 0.8f, 1.0f].ptr);
148         glBindTexture(GL_TEXTURE_2D, rope_texture);
149         
150         foreach(i; a..b)
151         {
152             if (i == cut_segm) continue;
153             
154             float[3] rs0 = (i>0 ? rope[i-1] : rope[i]);
155             float[3] rs1 = rope[i];
156             float[3] rs2 = rope[i+1];
157             float[3] rs3 = (i<rope.length-2 ? rope[i+2] : rope[i+1]);
158 
159             float[3] rs10 = rs0[] - rs1[];
160             float[3] rs12 = rs2[] - rs1[];
161             if (length(rs10) < 0.001) rs10[] = -rs12[];
162             normalize(rs10);
163             normalize(rs12);
164 
165             float[3] v10, v11, v12, v13;
166 
167             float[3] rs10m12 = rs10[] - rs12[];
168             float[3] rs10p12 = rs10[] + rs12[];
169             if (length(rs10m12) < 0.001 || length(rs10p12) < 0.001)
170             {
171                 //ax+by+cz = 0
172                 if (abs(rs12[0]) > 0.01 && abs(rs12[1]) > 0.01 && abs(rs12[2]) > 0.01)
173                 {
174                     v10 = [-rs12[1]/rs12[0], 1.0, 0.0];
175                     v11 = [-rs12[2]/rs12[0], 0.0, 1.0];
176                     normalize(v10);
177                     normalize(v11);
178                 }
179                 else if (abs(rs12[0]) > 0.01 && abs(rs12[1]) > 0.01)
180                 {
181                     v10 = [-rs12[1]/rs12[0], 1.0, 0.0];
182                     v11 = [0.0, 0.0, 1.0];
183                     normalize(v10);
184                 }
185                 else if (abs(rs12[0]) > 0.01 && abs(rs12[2]) > 0.01)
186                 {
187                     v10 = [-rs12[2]/rs12[0], 0.0, 1.0];
188                     v11 = [0.0, 1.0, 0.0];
189                     normalize(v10);
190                 }
191                 else if (abs(rs12[1]) > 0.01 && abs(rs12[2]) > 0.01)
192                 {
193                     v10 = [1.0, 0.0, 0.0];
194                     v11 = [0.0, 1.0, -rs12[1]/rs12[2]];
195                     normalize(v11);
196                 }
197                 else if (abs(rs12[0]) > 0.01)
198                 {
199                     v10 = [0.0, 1.0, 0.0];
200                     v11 = [0.0, 0.0, 1.0];
201                 }
202                 else if (abs(rs12[1]) > 0.01)
203                 {
204                     v10 = [1.0, 0.0, 0.0];
205                     v11 = [0.0, 0.0, 1.0];
206                 }
207                 else if (abs(rs12[2]) > 0.01)
208                 {
209                     v10 = [0.0, 1.0, 0.0];
210                     v11 = [1.0, 0.0, 0.0];
211                 }
212             }
213             else
214             {
215                 v10 = rs10p12;
216                 v11 = produce(rs10, rs12);
217                 normalize(v10);
218                 normalize(v11);
219             }
220             
221             v12[] = -v10[];
222             v13[] = -v11[];
223 
224             float[3] rs21 = rs1[] - rs2[];
225             float[3] rs23 = rs3[] - rs2[];
226             if (length(rs23) < 0.001) rs23[] = -rs21[];
227             normalize(rs21);
228             normalize(rs23);
229 
230             float[3] v20, v21, v22, v23;
231 
232             float[3] rs21m23 = rs21[] - rs23[];
233             float[3] rs21p23 = rs21[] + rs23[];
234             if (length(rs21m23) < 0.001 || length(rs21p23) < 0.001)
235             {
236                 //ax+by+cz = 0
237                 if (abs(rs21[0]) > 0.01 && abs(rs21[1]) > 0.01 && abs(rs21[2]) > 0.01)
238                 {
239                     v20 = [-rs21[1]/rs21[0], 1.0, 0.0];
240                     v21 = [-rs21[2]/rs21[0], 0.0, 1.0];
241                     normalize(v20);
242                     normalize(v21);
243                 }
244                 else if (abs(rs21[0]) > 0.01 && abs(rs21[1]) > 0.01)
245                 {
246                     v20 = [-rs21[1]/rs21[0], 1.0, 0.0];
247                     v21 = [0.0, 0.0, 1.0];
248                     normalize(v20);
249                 }
250                 else if (abs(rs21[0]) > 0.01 && abs(rs21[2]) > 0.01)
251                 {
252                     v20 = [-rs21[2]/rs21[0], 0.0, 1.0];
253                     v21 = [0.0, 1.0, 0.0];
254                     normalize(v20);
255                 }
256                 else if (abs(rs21[1]) > 0.01 && abs(rs21[2]) > 0.01)
257                 {
258                     v20 = [1.0, 0.0, 0.0];
259                     v21 = [0.0, 1.0, -rs21[1]/rs21[2]];
260                     normalize(v21);
261                 }
262                 else if (abs(rs21[0]) > 0.01)
263                 {
264                     v20 = [0.0, 1.0, 0.0];
265                     v21 = [0.0, 0.0, 1.0];
266                 }
267                 else if (abs(rs21[1]) > 0.01)
268                 {
269                     v20 = [1.0, 0.0, 0.0];
270                     v21 = [0.0, 0.0, 1.0];
271                 }
272                 else if (abs(rs21[2]) > 0.01)
273                 {
274                     v20 = [0.0, 1.0, 0.0];
275                     v21 = [1.0, 0.0, 0.0];
276                 }
277             }
278             else
279             {
280                 v20 = rs21p23;
281                 v21 = produce(rs21, rs23);
282                 normalize(v20);
283                 normalize(v21);
284             }
285             
286             v22[] = -v20[];
287             v23[] = -v21[];
288 
289             v10[] /= 8;
290             v11[] /= 8;
291             v12[] /= 8;
292             v13[] /= 8;
293             v20[] /= 8;
294             v21[] /= 8;
295             v22[] /= 8;
296             v23[] /= 8;
297 
298             float[3] r10 = v10[] + rs1[];
299             float[3] r11 = v11[] + rs1[];
300             float[3] r12 = v12[] + rs1[];
301             float[3] r13 = v13[] + rs1[];
302 
303             float[3] r20 = v20[] + rs2[];
304             float[3] r21 = v21[] + rs2[];
305             float[3] r22 = v22[] + rs2[];
306             float[3] r23 = v23[] + rs2[];
307 
308             float tx1 = 1.0*i/(rope.length-1);
309             float tx2 = 1.0*(i+1)/(rope.length-1);
310 
311             glBegin(GL_POLYGON);
312             glTexCoord2f(tx1, 0.0);
313             glNormal3fv(v10.ptr);
314             glVertex3fv(r10.ptr);
315 
316             glTexCoord2f(tx2, 0.0);
317             glNormal3fv(v20.ptr);
318             glVertex3fv(r20.ptr);
319 
320             glTexCoord2f(tx2, 0.25);
321             glNormal3fv(v21.ptr);
322             glVertex3fv(r21.ptr);
323 
324             glTexCoord2f(tx1, 0.25);
325             glNormal3fv(v11.ptr);
326             glVertex3fv(r11.ptr);
327             glEnd();
328 
329             glBegin(GL_POLYGON);
330             glTexCoord2f(tx1, 0.25);
331             glNormal3fv(v11.ptr);
332             glVertex3fv(r11.ptr);
333 
334             glTexCoord2f(tx2, 0.25);
335             glNormal3fv(v21.ptr);
336             glVertex3fv(r21.ptr);
337 
338             glTexCoord2f(tx2, 0.50);
339             glNormal3fv(v22.ptr);
340             glVertex3fv(r22.ptr);
341 
342             glTexCoord2f(tx1, 0.50);
343             glNormal3fv(v12.ptr);
344             glVertex3fv(r12.ptr);
345             glEnd();
346 
347             glBegin(GL_POLYGON);
348             glTexCoord2f(tx1, 0.50);
349             glNormal3fv(v12.ptr);
350             glVertex3fv(r12.ptr);
351 
352             glTexCoord2f(tx2, 0.50);
353             glNormal3fv(v22.ptr);
354             glVertex3fv(r22.ptr);
355 
356             glTexCoord2f(tx2, 0.75);
357             glNormal3fv(v23.ptr);
358             glVertex3fv(r23.ptr);
359 
360             glTexCoord2f(tx1, 0.75);
361             glNormal3fv(v13.ptr);
362             glVertex3fv(r13.ptr);
363             glEnd();
364 
365             glBegin(GL_POLYGON);
366             glTexCoord2f(tx1, 0.75);
367             glNormal3fv(v13.ptr);
368             glVertex3fv(r13.ptr);
369 
370             glTexCoord2f(tx2, 0.75);
371             glNormal3fv(v23.ptr);
372             glVertex3fv(r23.ptr);
373 
374             glTexCoord2f(tx2, 1.00);
375             glNormal3fv(v20.ptr);
376             glVertex3fv(r20.ptr);
377 
378             glTexCoord2f(tx1, 1.00);
379             glNormal3fv(v10.ptr);
380             glVertex3fv(r10.ptr);
381             glEnd();
382         }
383     }
384 
385     override bool tick(GlobalState gs)
386     {
387         if (rope.length > 1)
388         {
389             for (size_t i = rope.length-2; i >= static_segments; i--)
390             {
391                 float[3] r1 = rope[i+1];
392                 float[3] r2 = rope[i];
393                 float[3] r3 = rope[i-1];
394 
395                 if (i == cut_segm)
396                     r1 = rope[i];
397                 else if (i+1 == cut_segm)
398                     r3 = rope[i];
399 
400                 bool moved;
401                 float[3] l12 = r1[] - r2[];
402                 float[3] l23 = r3[] - r2[];
403 
404                 if (length(l12) > segl || length(l23) > segl)
405                 {
406                     if (cut_segm >= 0)
407                     {
408                         float[3] l13 = r1[] - r3[];
409                         float len = length(l13);
410 
411                         if (i <= cut_segm)
412                         {
413                             if (r1[1] < r3[1])
414                             {
415                                 rope[i][] = r1[]*segl/len + r3[]*(len-segl)/len;
416                                 moved = true;
417                             }
418                         }
419                         else
420                         {
421                             if (r3[1] < r1[1])
422                             {
423                                 rope[i][] = r1[]*(len-segl)/len + r3[]*segl/len;
424                                 moved = true;
425                             }
426                         }
427                     }
428                     else
429                     {
430                         rope[i][] = (r1[] + r3[])/2;
431                         moved = true;
432                     }    
433                 }
434 
435                 if (!moved && rope[i][1] > by)
436                 {
437                     rope[i][1] -= 0.1;
438                     
439                     r2 = rope[i];
440                     l12[] = r1[] - r2[];
441                     l23[] = r3[] - r2[];
442 
443                     if (cut_segm < 0)
444                     {
445                         if (length(l12) > segl || length(l23) > segl)
446                         {
447                             float dy;
448                             
449                             if ( length(l12) > length(l23) )
450                                 dy = sqrt(segl^^2 - l12[0]^^2 - l12[2]^^2) - l12[1];
451                             else
452                                 dy = sqrt(segl^^2 - l23[0]^^2 - l23[2]^^2) - l23[1];
453     
454                             rope[i][1] -= dy;
455                         }
456                     }
457                     else
458                     {
459                         if (i <= cut_segm)
460                         {
461                             if (length(l23) > segl)
462                                 rope[i][1] -= sqrt(segl^^2 - l23[0]^^2 - l23[2]^^2) - l23[1];
463                         }
464                         else
465                         {
466                             if (length(l12) > segl)
467                                 rope[i][1] -= sqrt(segl^^2 - l12[0]^^2 - l12[2]^^2) - l12[1];
468                         }
469                     }
470                 }
471             }
472         }
473 
474         return true;
475     }    
476 
477     override void load(string[string] s)
478     {
479         string p = "rope"~number.to!(string);
480         if (p~"-cut" in s)
481             cut_segm = s[p~"-cut"].to!(int);
482         else
483             cut_segm = -1;
484             
485         foreach(i; 0..10)
486         {
487             tick(null);
488         }
489     }
490 
491     override void save(ref string[string] s)
492     {
493         string p = "rope"~number.to!(string);
494         if (cut_segm >= 0)
495             s[p~"-cut"] = cut_segm.to!(string);
496     }    
497 }
498